package com.express.gateway.spi.auth.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.express.gateway.common.CommonCons;
import com.express.gateway.common.GatewayAttribute;
import com.express.gateway.common.ResultFormat;
import com.express.gateway.manage.enums.ContentTypeEnum;
import com.express.gateway.manage.enums.ParamPositionEnum;
import com.express.gateway.manage.enums.StatusCodeEnum;
import com.express.gateway.spi.auth.Auth;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWTToken权限认证实现类
 *
 * @author onemy
 */
public class AuthJwtTokenImpl implements Auth {
    private static final Logger LOG = LogManager.getLogger(AuthJwtTokenImpl.class);
    /**
     * 存放Session中token值key的名字
     */
    private ParamPositionEnum userTokenScope = ParamPositionEnum.HEADER;
    // 请求头中token值的key
    private final String apiTokenName;
    // 请求头中username值的key
    private final String userTokenName;
    // 认证失败返回结果的contentType,默认json-utf8
    private final ContentTypeEnum authFailContentType;
    // 认证失败返回结果
    private final String authFailResult;
    // 用户key的map;
    private final Map<String, String> userKeyMap = new HashMap<>();

    @Override
    public void handle(RoutingContext event) {
        String token = event.request().getHeader(apiTokenName);
        String username = event.request().getHeader(userTokenName);
        HttpServerResponse response = event.response().putHeader(CommonCons.SERVER, GatewayAttribute.FULL_NAME).putHeader(CommonCons.CONTENT_TYPE, authFailContentType.val());
        if (username == null || username.isEmpty()) {
            response.end(authFailResult);
            return;
        }

        // 务器中token值对应用户 secretKeys -> {username, secretKey}数据对
        String secretKey = userKeyMap.get(username);
        LOG.info("userKey:" + secretKey);
        if (secretKey == null || secretKey.isEmpty()) {
            response.end(authFailResult);
            return;
        }

        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secretKey)).build();
        DecodedJWT jwt = null;
        try {
            jwt = verifier.verify(token);
            event.next();
        } catch (Exception e) {
            LOG.error("jwt token is invalid: {}", e.getMessage());
            response.end(authFailResult);
            return;
            //throw new RuntimeException("凭证无效或己过期！");
        }

//        public String getToken (User user){
//            //过期时间，5分钟
//            Long EXPIRE_TIME = 5 * 60 * 1000L;
//            //生成过期时间
//            Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//            // 将 user id 保存到 token 里面
//            String token = JWT.create().withAudience(user.getId())
//                    // 设需过期时间
//                    .withExpiresAt(expireDate)
//                    // 以 password 作为 token 的密钥
//                    .sign(Algorithm, HMAC256(user.getPassword()));
//            return token;
//        }
    }

    /**
     * @param obj 通过一个JsonObject实例化一个对象 <br>
     *            obj.apiTokenName = API中token的名字<br>
     *            obj.userTokenName = 用户token在请求中的名字<br>
     *            obj.userTokenScope =
     *            用户token在请求中的名字所在的位置枚举类型{@link ParamPositionEnum} 默认在HEADER中<br>
     *            obj.authFailContentType =
     *            验证不通过时返回的Content-Type枚举类型{@link ContentTypeEnum} 默认为JSON_UTF8<br>
     *            obj.authFailResult = 验证不通过时的返回结果 默认为
     *            {@link ResultFormat}.formatAsNull({@link StatusCodeEnum}.C401)<br>
     */
    public AuthJwtTokenImpl(JsonObject obj) {
        if (obj == null) {
            throw new NullPointerException("JwtToken认证方式的配置文件不能为空!");
        }

        if (obj.getValue("apiTokenName") instanceof String) {
            this.apiTokenName = obj.getString("apiTokenName");
        } else {
            this.apiTokenName = CommonCons.KEY_JWT_TOKEN_NAME;
        }

        if (obj.getValue("userTokenName") instanceof String) {
            this.userTokenName = obj.getString("userTokenName");
        } else {
            this.userTokenName = CommonCons.KEY_JWT_USER_TOKEN_NAME;
        }

        // 用户请求token存放的位置,默认为header
        if (obj.getValue("userTokenScope") instanceof String) {
            userTokenScope = ParamPositionEnum.valueOf(obj.getString("userTokenScope"));
        } else {
            userTokenScope = ParamPositionEnum.HEADER;
        }

        if (obj.getValue("authFailContentType") instanceof String) {
            this.authFailContentType = ContentTypeEnum.valueOf(obj.getString("authFailContentType"));
        } else {
            this.authFailContentType = ContentTypeEnum.JSON_UTF8;
        }

        if (obj.getValue("authFailResult") instanceof String) {
            this.authFailResult = obj.getString("authFailResult");
        } else {
            this.authFailResult = ResultFormat.formatAsNull(StatusCodeEnum.C401);
        }
        // 解析服务端配置的 {name, key}数据对
        if (obj.getJsonArray("secretKeys") != null) {
            JsonArray userKeys = obj.getJsonArray("secretKeys");
            userKeys.forEach(item -> {
                JsonObject useKey = JsonObject.mapFrom(item);
                useKey.iterator().forEachRemaining(entry -> {
                    userKeyMap.put(entry.getKey(), entry.getValue().toString());
                });
            });
        }

    }
}
